﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebSysCore.Helpers;

namespace WebSysCore
{
    public class Scheduling
    {
        /// <summary>
        /// Định nghĩa loài cần cho tiến hóa
        /// </summary>
        private class School
        {
            /// <summary>
            /// Nucleotit vế trái - Môn học
            /// </summary>
            public class S
            {
                public int ID { get; set; }
            }

            /// <summary>
            /// Nucleotit vế phải - Giáo viên
            /// </summary>
            public class T
            {
                public int ID { get; set; }
            }

            /// <summary>
            /// Cặp nucleotit
            /// </summary>
            public class Gen
            {
                public Boolean fix { get; set; }
                public S s { get; set; }
                public T t { get; set; }
            }

            /// <summary>
            /// Một gen là một chuỗi gồm một hay nhiều cặp nucleotit liên tiếp nhau nhưng có cùng môn học và giáo viên
            /// </summary>


            /// <summary>
            /// Qui tắc ghép cặp của Nucleotit
            /// </summary>
            public class Rule
            {
                public bool fix = false;
                public S s;
                public int require;
                public List<T> lstT;
                public int selected;
            }
            /// <summary>
            /// Danh sach cac qui tac ghep cap cua nucleotit ap dung chung cho tat ca
            /// cac nhiem sac the.
            /// </summary>
            public List<Rule> lstRules;

            /// <summary>
            /// Một nhiễm sắc thể đại diện cho một thời khóa biểu của một lớp.
            /// </summary>
            public class Chromosome
            {
                public Class cl;
                public List<Rule> lstRules;
                //Cấu tạo của nhiễm sắc thể (Schema)
                public List<Subject> lstSub;
                public List<int> lstNum;
                public List<int> lstUse;

                public List<Day> lstD;
                public List<Lession> lstL;
                public List<FixSubjectSessionLession> lstFix;

                //public List<Gen> nuString;
                public List<Gen> genString;
                //Khởi tạo một nhiễm sắc thể
                public Chromosome(int schId, int classId)
                {
                    //Khởi tạo một chromosome từ thông tin của một lớp.


                    //Khởi tạo luật ghép riêng của nhiễm sắc thể hiện tại.
                    cl = DataBase.GetClassById(classId);
                    lstRules = new List<Rule>();
                    List<Subject> lstAllSub = DataBase.GetSubjectOfClass(classId);
                    foreach (Subject s in lstAllSub)
                    {
                        Rule r = new Rule();
                        FixTeacherClassSubject fix = DataBase.GetFCST(schId, classId, s.SubjectID);
                        if (fix != null)
                        {
                            r.s = new S() { ID = s.SubjectID };
                            r.require = s.Require;
                            r.lstT = new List<T>();
                            r.lstT.Add(new T() { ID = fix.TeacherID });
                            r.fix = true;
                        }
                        else
                        {
                            r.s = new S() { ID = s.SubjectID };
                            r.require = s.Require;
                            List<Teacher> lstT = DataBase.GetTeacherOfSubject(s.SubjectID);
                            r.lstT = new List<T>();
                            foreach (Teacher t in lstT)
                            {
                                r.lstT.Add(new T() { ID = t.TeacherID });
                            }

                        }
                        lstRules.Add(r);
                    }

                    List<ProgramDetail> lstDetail = DataBase.GetProgramOfClass(cl.ClassID);

                    lstSub = new List<Subject>();
                    lstNum = new List<int>();
                    lstUse = new List<int>();
                    foreach (ProgramDetail dt in lstDetail)
                    {
                        lstSub.Add(DataBase.GetSubjectByID(dt.SubjectID));
                        lstNum.Add(dt.NumLession);
                        lstUse.Add(0);
                    }
                    lstFix = DataBase.GetFixSubjectGroup(cl.GroupID);

                    //Khởi tạo chuổi gen với những điểm cố định.
                    genString = new List<Gen>();
                    //Randomize một chuỗi gen cho nhiễm sắc thể này.
                    lstD = DataBase.GetAllDay(schId);
                    var query = from q in lstD
                                where q.DayName.Equals("All")
                                select q;
                    if (query.Count() > 0)
                    {
                        lstD.Remove(query.ToList()[0]);
                    }

                    //lstD.Sort(new Comparison<Day>(Utils.DayCompare));
                    lstL = DataBase.GetAllLession(schId);
                    //lstL.Sort(new Comparison<Lession>(Utils.LessionCompare));

                    int chroLength = lstD.Count * lstL.Count;
                    while (genString.Count < chroLength)
                    {
                        int cDId, cLId, cDPos, cLPos;
                        cDPos = genString.Count / lstL.Count;
                        cLPos = genString.Count % lstL.Count;
                        cDId = lstD[cDPos].DayID;
                        cLId = lstL[cLPos].LessionID;
                        //Teacher all = DataBase.GetTeacherNone();
                        bool isFix = false;
                        FixSubjectSessionLession fi = null;
                        foreach (FixSubjectSessionLession f in lstFix)
                        {
                            if (f.DayID == cDId && f.LessionID == cLId)
                            {
                                isFix = true;
                                fi = f;
                                break;

                                //g.ADNSeg=
                                //genString.Add(new Gen() { ADNSeg=new List<Pair> });
                            }
                        }
                        if (isFix)
                        {
                            int id = 0;
                            Subject su = DataBase.GetSubjectByID(fi.SubjectID);
                            id = lstSub.IndexOf(su);
                            Rule r = GetRule(su.SubjectID);
                            Random rn = new Random();
                            int rVall = GetNeedLength(su.SubjectID);
                            int tId = rn.Next(r.lstT.Count - 1);
                            for (int i = 0; i < rVall; i++)
                            {
                                Gen g = new Gen() { fix = true, s = new S() { ID = su.SubjectID }, t = r.lstT[tId] };
                                genString.Add(g);
                            }
                            //Gen g = new Gen(fi.SubjectID, r.lstT[rVall].ID, su.Require);
                            //genString.Add(g);
                            //Cập nhật bảng phân công giáo viên

                            lstUse[id] += rVall;

                        }
                        else
                        {
                            //Random nao

                            //Lay danh sach cac mon chua du
                            List<Subject> lstNeedSub;
                            lstNeedSub = new List<Subject>();
                            for (int i = 0; i < lstSub.Count; i++)
                            {
                                if (lstUse[i] < lstNum[i])
                                {
                                    lstNeedSub.Add(lstSub[i]);
                                }
                            }
                            if (lstNeedSub.Count > 0)
                            {
                                Random r = new Random();
                                int ranPos = r.Next(lstNeedSub.Count - 1);
                                //Gen g = new Gen();
                                int dPos, lPos;
                                GetPos(genString.Count, out dPos, out lPos);
                                while (!CheckSuitable(lstNeedSub[ranPos], dPos, lPos))
                                {
                                    ranPos = r.Next(lstNeedSub.Count - 1);
                                }
                                int rVal = GetNeedLength(lstNeedSub[ranPos].SubjectID);
                                Rule r1 = GetRule(lstNeedSub[ranPos].SubjectID);
                                int rT = r.Next(r1.lstT.Count - 1);
                                for (int i = 0; i < rVal; i++)
                                {
                                    Gen g = new Gen() { fix = false, s = new S() { ID = lstNeedSub[ranPos].SubjectID }, t = r1.lstT[rT] };
                                    genString.Add(g);
                                }
                            }



                        }
                    }

                }

                public int GetNeedLength(int subId)
                {
                    var query = from q in lstSub
                                where q.SubjectID == subId
                                select q;
                    if (query.Count() > 0)
                    {
                        Subject s = query.ToList()[0];
                        int pos = 0;
                        for (int i = 0; i < lstSub.Count; i++)
                        {
                            if (lstSub[i].SubjectID == s.SubjectID)
                            {
                                pos = i;
                                break;
                            }
                        }
                        int need = (lstNum[pos] - lstUse[pos]) > s.Require ? s.Require : lstNum[pos] - lstUse[pos];
                        return need;
                    }
                    else
                    {
                        return 0;
                    }
                }

                public Rule GetRule(int subId)
                {
                    var query = from q in lstRules
                                where q.s.ID == subId
                                select q;
                    if (query.Count() > 0)
                    {
                        return query.ToList()[0];
                    }
                    else
                    {
                        return null;
                    }
                }
                public void GetPos(int genPos, out int dPos, out int lPos)
                {
                    dPos = 0;
                    lPos = 0;
                    dPos = genPos / lstL.Count;
                    lPos = genPos % lstL.Count;
                }
                public bool CheckSuitable(Subject s, int dPos, int lPos)
                {
                    bool ok = true;
                    if (lPos + s.Require >= lstL.Count)
                    {
                        ok = false;
                    }
                    if (ok)
                    {
                        //FixSubjectSessionLession fi=(se);
                        for (int i = lPos; i < lPos + s.Require; i++)
                        {
                            var query = from q in lstFix
                                        where q.SubjectID == s.SubjectID && q.DayID == lstD[dPos].DayID && q.LessionID == lstL[i].LessionID
                                        select q;
                            if (query.Count() > 0)
                            {
                                ok = false;
                                break;
                            }
                        }
                    }
                    return ok;
                }

                public bool CheckState()
                {
                    bool ok = true;
                    for (int i = 0; i < lstSub.Count; i++)
                    {
                        if (lstNum[i] < lstUse[i])
                        {
                            ok = false;
                            break;
                        }
                    }
                    return ok;
                }

                /// <summary>
                /// Đột biến
                /// </summary>
                public void Mutant()
                {
                }


                /// <summary>
                /// Ghép đôi (sinh sản)
                /// </summary>
                /// <param name="c1"></param>
                /// <param name="c2"></param>
                /// <returns></returns>
                public static Chromosome Combine(Chromosome c1, Chromosome c2)
                {
                    //Chromosome s = new Chromosome();
                    return null;
                }
            }

            //Một cá thể (School) được qui định bởi n nhiễm sắc thể.
            public List<Chromosome> lstChro;

            public School(int scheduleIdInList, bool cracked)
            {

                //Load các quy tắc ghép đôi của Nucleotit
                lstRules = new List<Rule>();
                List<Subject> lstAllSub = DataBase.GetAllSubjectOfSchedule(scheduleIdInList);
                foreach (Subject s in lstAllSub)
                {
                    List<Teacher> lstTeacher = DataBase.GetTeacherOfSubject(s.SubjectID);
                    Rule r = new Rule();
                    r.s = new S() { ID = s.SubjectID };
                    r.lstT = new List<T>();
                    foreach (Teacher t in lstTeacher)
                    {
                        r.lstT.Add(new T() { ID = t.TeacherID });
                    }
                    lstRules.Add(r);
                }
                //Khởi tạo các nhiễm sắc thể.
                List<Class> lstAllClass = DataBase.GetAllClass(scheduleIdInList);
                lstChro = new List<Chromosome>();
                //Với mỗi Class trong trường ta có một nhiễm sắc thể qui định cá thể trường học
                foreach (Class c in lstAllClass)
                {
                    //Chr
                }


            }
        }
    }
}
